Shader "XJ4/Character/Standard"
{
	Properties
	{
		_Color("Main Color", Color) = (1, 1, 1, 1)
		[HDR]_HighColor("High Color", Color) = (1, 1, 1, 1)
		

		_MainTex("Diffuse", 2D) = "white" {}

		//[NoScaleOffset]_DiffuseControl("Diffuse Control", 2D) = "white" {}

		[NoScaleOffset]_NormalMap("Normal", 2D) = "bump" {}


		[NoScaleOffset]_SpecTex("Metal(R) Aniso(G) Roughness(B)", 2D) = "black" {}

		_Fresnel("Fresnel Strength", Range(0.0,1.0)) = 0.5
		_Shineness("Shineness", Range(2.0,16.0)) = 16
		_Sharpness("Smoothness", Range(0.0,8.0)) = 4.0
		_Aniso("Aniso Power", Range(0.0,4.0)) = 2.0

		_RimColor("Rim Color", Color) = (0.0, 0.0, 0.0, 1)

		_BackLightDirXYZGlossW("Rim V", Vector) = (0.0, 0.0, 0.0, 0.1)

		_AdjustMap("AdjustMap", 2D) = "black" {}
		[HDR]_AdjustColor_R ("AdjustColor_R", Color) = (0.0, 0.0, 0.0, 0.0)
		[HDR]_AdjustColor_G ("AdjustColor_G", Color) = (0.0, 0.0, 0.0, 0.0)
		[HDR]_AdjustColor_B ("AdjustColor_B", Color) = (0.0, 0.0, 0.0, 0.0)

		[HideInInspector]_Clip("Clip",Range(0,1.0)) = 0.5

		[Space]
		[HideInInspector][Enum(UnityEngine.Rendering.BlendMode)] _SrcBlend("Src Blend Mode", Float) = 5
		[HideInInspector][Enum(UnityEngine.Rendering.BlendMode)] _DstBlend("Dst Blend Mode", Float) = 10

		//_CharaMaskColor("Mask Color", Color) = (0.05, 0.67, 1, 1)
	}

		SubShader
		{
			Tags
			{
				"RenderType" = "Opaque"
				"Queue" = "AlphaTest+1"
				"LightMode" = "ForwardBase"
			}

		//	Pass
		//	{

		//		ZTest Greater
		//		ZWrite Off
		//		Blend OneMinusDstColor One

		//		CGPROGRAM
		//		#pragma vertex vert
		//		#pragma fragment frag
		//		#pragma fragmentoption ARB_precision_hint_fastest            
		//		#include "UnityCG.cginc"

		//		sampler2D _MainTex;
		//		float4 _MainTex_ST;
		//		fixed4 _CharaMaskColor;

		//		struct vsIn
		//		{
		//			float4 vertex : POSITION;
		//			float2 texcoord : TEXCOORD0;
		//		};

		//		struct vsOut
		//		{
		//			float4 vertex : SV_POSITION;
		//			float2 uv : TEXCOORD0;
		//		};

		//		vsOut vert(vsIn v)
		//		{
		//			vsOut o;
		//			o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
		//			o.uv.xy = TRANSFORM_TEX(v.texcoord.xy, _MainTex);
		//			return o;
		//		}

		//		fixed4 frag(vsOut In) : SV_Target
		//		{
		//			fixed4 albedoColor = tex2D(_MainTex, In.uv.xy);
		//			return albedoColor * _CharaMaskColor;
		//		}

		//	ENDCG
		//}

		Pass
		{
			Cull Back
			ZTest LEqual
			Blend [_SrcBlend] [_DstBlend]
			CGPROGRAM
				#pragma target 3.0
				#pragma exclude_renderers gles
				#pragma multi_compile_fwdbase
				#pragma multi_compile_fog

				#pragma multi_compile __ XJ4_PROJECTTEX XJ4_REFRESH_ON

				#pragma vertex vert
				#pragma fragment frag
				#include "UnityCG.cginc"
				#include "AutoLight.cginc"
				#include "Lighting.cginc"

				float4 _Color;
				float4 _HighColor;
				float4 _RimColor;
				float4 _MainTex_ST;
				float _Shineness;
				float _Sharpness;
				sampler2D _NormalMap;
				float _Clip;
				float _Aniso;
				float4 _BackLightDirXYZGlossW;

				sampler2D _AdjustMap;
				fixed4 _AdjustColor_R;
				fixed4 _AdjustColor_G;
				fixed4 _AdjustColor_B;

				inline half3 ComputeAlbedo(float2 uv, half4 c)
				{
					fixed3 adj = tex2D(_AdjustMap, uv);
					fixed4 adjColor = adj.r * _AdjustColor_R + adj.g * _AdjustColor_G + adj.b * _AdjustColor_B;
					fixed adjFactor = max(max(adj.r, adj.g), adj.b);
					fixed brightness = lerp(1, max(c.r, max(c.g, c.b)), adjColor.a);
					adjColor.rgb = lerp(c.rgb, adjColor.rgb, adjColor.a);
					half3 o = lerp(c.rgb, brightness * adjColor.rgb, adjFactor);
					return o;
				}

				// Textures
				sampler2D _MainTex;
				sampler2D _SpecTex;
				sampler2D _DiffuseControl;


#if defined (XJ4_PROJECTTEX)
				uniform sampler2D _CloudShadowTex;
				uniform float4	_CloudOffset;
				uniform float _CloudShadowStrength;
				uniform float _CloudShadowSign;
				uniform float4 _CloudScale;
				uniform float4 _CloudBackColor;
				uniform float _CloudTime;
#endif



				// Structure from vertex shader to fragment shader
				struct v2f
				{
					float4 pos    : SV_POSITION;
					half3 tspace0 : TEXCOORD0;
					SHADOW_COORDS(1)
					float4 uv     : TEXCOORD2;
					float3 worldPos : TEXCOORD3;
					float4 lightDir : TEXCOORD4;
					UNITY_FOG_COORDS(5)
					half3 tspace1 : TEXCOORD6;
					half3 tspace2 : TEXCOORD7;
				};


				// Float types
				#define float_t  half
				#define float2_t half2
				#define float3_t half3
				#define float4_t half4

				uniform half	_Fresnel;

				inline half3 specCubeLookup(samplerCUBE specCube, float3 worldRefl) {
					half4 spec = texCUBE(specCube, worldRefl);
					return spec;
				}
				
				inline half3 fromRGBM(half4 c) {
					c.a *= 6.0;
					return c.rgb * c.a;
				}

				float Smooth(float x) {
					return x + (x - (x * x * (3.0f - 2.0f * x)));
				}

				inline float Smooth2(float x) {
					x -= 0.5;
					return 0.5 + 4 * x*x*x;
				}

				inline half3 glossCubeLookup(float3 worldRefl, float lod) {

					half4 skyData = UNITY_SAMPLE_TEXCUBE_LOD(unity_SpecCube0, worldRefl, _Sharpness * Smooth(lod));
					//return fromRGBM(skyData )* unity_SpecCube0_HDR.r;
					return (skyData)* unity_SpecCube0_HDR.r;
				}

				inline half fastFresnel(half3 NdotE, half fresnel) {
					//fresnel math performed in gamma space
					half factor = 1.0 - saturate(NdotE);
					factor *= 0.5 + 0.5*factor;
					factor = 0.15 + factor*0.85;
					factor = lerp(1.0, factor, fresnel);
					return factor;
				}

				// Vertex shader
				v2f vert(appdata_tan v)
				{
					v2f o;
					o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
					o.uv.xy = TRANSFORM_TEX(v.texcoord.xy, _MainTex);

					half3 normal = UnityObjectToWorldNormal(v.normal);

					// Eye direction vector
					float4_t worldPos = mul(unity_ObjectToWorld, v.vertex);

#if defined (XJ4_PROJECTTEX)
					o.uv.zw = _CloudOffset.zw * (worldPos.xz - _CloudOffset.xy);
#else
					o.uv.zw = 0;
#endif

					o.worldPos = worldPos.xyz;

					o.lightDir.rgb = WorldSpaceLightDir(v.vertex);
					o.lightDir.a = 0;

					half3 wTangent = UnityObjectToWorldDir(v.tangent.xyz);
					half tangentSign = v.tangent.w * unity_WorldTransformParams.w;
					half3 wBitangent = cross(normal, wTangent) * tangentSign;
					o.tspace0 = half3(wTangent.x, wBitangent.x, normal.x);
					o.tspace1 = half3(wTangent.y, wBitangent.y, normal.y);
					o.tspace2 = half3(wTangent.z, wBitangent.z, normal.z);

					TRANSFER_SHADOW(o);

					UNITY_TRANSFER_FOG(o, o.pos);
					return o;
				}

				inline float3 SHLookupUnity(float3 dir) {
					return ShadeSH9(half4(dir.x, dir.y, dir.z, 1.0));
				}

				inline float3 RotateAroundXInDegrees(float3 vertex, float degrees)
				{
					float alpha = degrees * UNITY_PI / 180.0;
					float sina, cosa;
					sincos(alpha, sina, cosa);
					float2x2 m = float2x2(cosa, -sina, sina, cosa);
					return float3(vertex.x, mul(m, vertex.yz));
				}

				// Fragment shader
				float4 frag(v2f i) : SV_Target
				{
					float4_t albedoColor = tex2D(_MainTex, i.uv.xy);
					albedoColor.rgb = ComputeAlbedo(i.uv.xy, albedoColor);

					half3 tnormal = UnpackNormal(tex2D(_NormalMap, i.uv));
					half3 worldNormal;
					worldNormal.x = dot(i.tspace0, tnormal);
					worldNormal.y = dot(i.tspace1, tnormal);
					worldNormal.z = dot(i.tspace2, tnormal);

					half3 skyN = worldNormal;

					half3 eyeDir = normalize(_WorldSpaceCameraPos - i.worldPos);
					
					half3 worldR = reflect(-eyeDir, worldNormal);

					half3 skyRefl = worldR;
					half NdotL = dot(worldNormal, i.lightDir);
					half NdotE = dot(worldNormal, eyeDir);
					half fresnela = fastFresnel(NdotE, _Fresnel);

					//spherical harmonics
					float3 diffuseIBL = SHLookupUnity(skyN);

					// Falloff. Convert the angle between the normal and the camera direction into a lookup for the gradient
					float_t albedo = clamp(1 - saturate(NdotE), 0.02, 0.98);

					// Rimlight
					float_t rimlightDot = 0.5 * NdotL + 0.5;
					float k_albedo = saturate(rimlightDot * albedo );
					//albedo = tex2D(_DiffuseControl, float2(k_albedo, 0.25f)).r;
					half l = tex2D(_DiffuseControl, float2(rimlightDot, 0.25f)).r;
					//albedo = lerp(albedo, l, k_albedo);
					albedo = lerp(k_albedo, 1, l);

					float4_t specMaskColor = tex2D(_SpecTex, i.uv.xy);

					float3_t halfAngle = normalize(eyeDir + i.lightDir);
					float_t hs = abs(dot(worldNormal, halfAngle));

					// norm = (n+2)/(2*pi)
					half normTerm = (specMaskColor.b + 2.0) * (0.25 / UNITY_PI);

					half TDotH = dot(normalize(half3(i.tspace0.y, i.tspace1.y, i.tspace2.y) + worldNormal * specMaskColor.g), halfAngle);
					float kDotH = 1 - TDotH * TDotH;
					kDotH = kDotH * normTerm + pow(kDotH, _Shineness * 4);
					float aniso = saturate(smoothstep(-1, 0, TDotH) * kDotH);

					float_t spec = lerp(normTerm * pow(hs, _Shineness * specMaskColor.b), aniso, specMaskColor.g * _Aniso);

					half3 ibl = glossCubeLookup(skyRefl, 1 - specMaskColor.b);

					float_t directLight = albedo;

					float_t attenuation = SHADOW_ATTENUATION(i);
					directLight *= attenuation;

					ibl = (spec + ibl) * _HighColor.rgb ;

	#if defined (XJ4_PROJECTTEX)
					float cloudBlend = tex2D(_CloudShadowTex, i.uv.zw * _CloudScale.x + _Time.x * _CloudScale.z).r;
					cloudBlend = lerp(cloudBlend, tex2D(_CloudShadowTex, i.uv.zw * _CloudScale.y + _Time.x * _CloudScale.w).r, _CloudTime);
					cloudBlend = (1 + _CloudShadowSign * saturate(cloudBlend * _CloudShadowStrength));
					directLight = lerp(_CloudBackColor.rgb, directLight, cloudBlend);
	#endif

					fixed3 lightingPoint = Shade4PointLights(
					unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0,
					unity_LightColor[0].rgb, unity_LightColor[1].rgb, unity_LightColor[2].rgb, unity_LightColor[3].rgb,
					unity_4LightAtten0, i.worldPos, worldNormal);
					
					fixed3 diff = (directLight * _LightColor0 + lightingPoint + diffuseIBL);

					fixed3 emissive = (pow(dot(((worldNormal*normalize(_BackLightDirXYZGlossW.rgb)) + _BackLightDirXYZGlossW.a), (1.0 - max(0, NdotE))), 10.0)*_RimColor.rgb);
					//fixed3 emissive = _RimColor.rgb * pow(k_albedo, 5);
					
					fixed3 combinedColor = (diff * albedoColor *(1 - specMaskColor.r) * _Color + ibl * lerp(0.04,albedoColor* fresnela + 1 - fresnela,specMaskColor.r)) + saturate(emissive);

					//return float4_t( combinedColor, diffSamplerColor.a ) * _Color * _LightColor0;
					float4_t final = float4_t(combinedColor, albedoColor.a);

					final.a *= _Color.a;

					clip(albedoColor.a - _Clip);

					UNITY_APPLY_FOG(i.fogCoord, final);
					return final;
				}

			ENDCG
		}

	}


	FallBack "Mobile/VertexLit"
}
